/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.muni.fi.pb138.videodes.impl;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import cz.muni.fi.pb138.videodes.api.base.XMLDBTemplate;
import cz.muni.fi.pb138.videodes.api.base.RowMapper;
import cz.muni.fi.pb138.videodes.entity.Dvd;
import cz.muni.fi.pb138.videodes.entity.DvdConverter;
import cz.muni.fi.pb138.videodes.entity.DvdType;
import cz.muni.fi.pb138.videodes.entity.Movie;
import java.util.List;

/**
 *
 * @author pseudo
 */
public class DvdManagerImpl implements DvdManager{

    @Override
    public void add(Dvd dvd) {
	if (dvd == null) {
	    throw new IllegalArgumentException("the parameter item cannot be null");
	}
	if (dvd.getId() != null) {
	    throw new IllegalArgumentException("the id of the given parameter cannot be set");
	}

	XStream x = new XStream(new DomDriver());
	x.registerConverter(new DvdConverter());
	x.alias("dvd", Dvd.class);
	x.alias("movie", Movie.class);

	String xml = x.toXML(dvd);
        
        if (!XMLValidation.validate(xml, "cz/muni/fi/pb138/videodes/files/dvdSchema.xsd")) {
            return;
        }

	String id =  XMLDBTemplate.storeResource("/dvd", xml);
	dvd.setId(id);
    }

    @Override
    public void remove(Dvd dvd) {
	if (dvd == null) {
	    throw new IllegalArgumentException("the parameter item cannot be null");
	}
        if (dvd.getId() == null) {
	    throw new IllegalArgumentException("the id of the given parameter must be set");
	}

	 XMLDBTemplate.removeResource("/dvd", dvd.getId());
    }
    
    @Override
    public void update(Dvd dvd) {
        if (dvd == null) {
            throw new IllegalArgumentException("the parameter item cannot be null");
        }
        if (dvd.getId() == null) {
            throw new IllegalArgumentException("the id of the given parameter must be set");
        }

        XStream x = new XStream(new DomDriver());
	x.registerConverter(new DvdConverter());
	x.alias("dvd", Dvd.class);
	x.alias("movie", Movie.class);

	String xml = x.toXML(dvd);
        
        if (!XMLValidation.validate(xml, "cz/muni/fi/pb138/videodes/files/dvdSchema.xsd")) {
            return;
        }

        XMLDBTemplate.updateResource("/dvd", xml, dvd.getId());
    }

    @Override
    public List<Dvd> getAllDvds() {
	RowMapper<Dvd> rowMapper = new DvdRowMapper();

	String xquery = "for $dvd in collection('/db/dvd')//dvd "
		+ "return <dvd id=\"{fn:substring(fn:base-uri($dvd), 9)}\">"
		+ "{$dvd/title}"
                + "{$dvd/type}"
		+ "{"
		+ "<content>"
		+ "	{"
		+ "	for $movie in $dvd/content//movie"
                + "     let $movieIn := doc(concat(\"/db/movie/\", $movie/@id))/movie"
		+ "		return "
                + "                    <movie id=\"{$movie/@id}\">"
                + "                          {$movieIn/name}"
                + "                          {$movieIn/director}"
                + "                          {$movieIn/year}"
                + "                          {$movieIn/country}"
                + "                          {$movieIn/actors}"
                + "                          {$movieIn/genres}"
                + "                    </movie>"
		+ "	}"
		+ "</content>"
		+ "}"
		+ "</dvd>";

	List<Dvd> dvds =  XMLDBTemplate.executeQueryAsList(xquery, rowMapper);

	return dvds;
    }
    
	
    @Override
    public Dvd getDvdById(String id) {
        if (id == null) {
            throw new IllegalArgumentException("the parameter id cannot be null");
        }
        if (id.isEmpty()) {
            throw new IllegalArgumentException("the parameter id cannot be empty");
        }
        
	RowMapper<Dvd> rowMapper = new DvdRowMapper();

	String xquery = "let $dvd := doc('/db/dvd/?')/dvd "
		+ "return <dvd id=\"{fn:substring(fn:base-uri($dvd), 9)}\">"
		+ "{$dvd/title}"
                + "{$dvd/type}"
		+ "{"
		+ "<content>"
		+ "	{"
		+ "	for $movie in $dvd/content//movie"
                + "     let $movieIn := doc(concat(\"/db/movie/\", $movie/@id))/movie"
		+ "		return "
                + "                    <movie id=\"{$movie/@id}\">"
                + "                          {$movieIn/name}"
                + "                          {$movieIn/director}"
                + "                          {$movieIn/year}"
                + "                          {$movieIn/country}"
                + "                          {$movieIn/actors}"
                + "                          {$movieIn/genres}"
                + "                    </movie>"
		+ "	}"
		+ "</content>"
		+ "}"
		+ "</dvd>";
	
	Dvd dvd =  XMLDBTemplate.executeQueryAsValue(xquery, rowMapper, id);
	if (dvd.getId().isEmpty()) {
	    throw new IllegalArgumentException("No element with an expected id retrieved from the database");
	}

	return dvd;
    }

    @Override
    public List<Dvd> getDvdsByType(DvdType type) {
        if (type == null) {
            throw new IllegalArgumentException("the parameter type cannot be null");
        }
        
	RowMapper<Dvd> rowMapper = new DvdRowMapper();

	String xquery = "for $dvd in collection('/db/dvd')//dvd "
		+ "where $dvd/type = '?'"
		+ "return <dvd id=\"{fn:substring(fn:base-uri($dvd), 9)}\">"
		+ "{$dvd/title}"
                + "{$dvd/type}"
		+ "{"
		+ "<content>"
		+ "	{"
		+ "	for $movie in $dvd/content//movie"
                + "     let $movieIn := doc(concat(\"/db/movie/\", $movie/@id))/movie"
		+ "		return "
                + "                    <movie id=\"{$movie/@id}\">"
                + "                          {$movieIn/name}"
                + "                          {$movieIn/director}"
                + "                          {$movieIn/year}"
                + "                          {$movieIn/country}"
                + "                          {$movieIn/actors}"
                + "                          {$movieIn/genres}"
                + "                    </movie>"
		+ "	}"
		+ "</content>"
		+ "}"
		+ "</dvd>";
	
	List<Dvd> dvds =  XMLDBTemplate.executeQueryAsList(xquery, rowMapper, type.toString());

	return dvds;
    }
}
